package testplugin;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.transaction.RecordingCommand;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.util.TransactionUtil;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gmf.runtime.diagram.ui.editparts.DiagramEditPart;
import org.eclipse.gmf.runtime.diagram.ui.parts.IDiagramWorkbenchPart;
import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.gmf.runtime.notation.impl.ShapeImpl;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.papyrus.infra.core.sasheditor.editor.ISashWindowsContainer;
import org.eclipse.papyrus.infra.core.services.ServicesRegistry;
import org.eclipse.papyrus.infra.core.utils.ServiceUtils;
import org.eclipse.papyrus.infra.core.utils.ServiceUtilsForActionHandlers;
import org.eclipse.papyrus.uml.diagram.clazz.part.UMLDiagramEditorUtil;
import org.eclipse.papyrus.uml.diagram.clazz.providers.UMLMarkerNavigationProvider;

import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPart;

import org.eclipse.ui.actions.WorkspaceModifyDelegatingOperation;

public class MarkersAndHighlightUtil extends Action
{
	/**
	 * Required for the markers
	 */
	private IWorkbenchPart workbenchPart;
	
	/**
	 *Required for the markers
	 */
	private Object objectToMarkAndHighlight;


	/**
	 * Required for the shapes
	 */
	private ISashWindowsContainer container;
	
	public MarkersAndHighlightUtil()
	{
	
	}

	/**
	 * 
	 * @param workbenchPart
	 */
	public void setWorkbenchPart(IWorkbenchPart workbenchPart)
	{
		this.workbenchPart = workbenchPart;
	}


	/**
	 * 
	 * @param objectToMarkTest
	 */
	public void setObjectsToMarkAndHighlight(Object objectToMarkTest)
	{
		this.objectToMarkAndHighlight = objectToMarkTest;
	}
	

	public void setContainer(ISashWindowsContainer container) {
		this.container = container;
	}
	
	public void run()
	{

		if( workbenchPart instanceof IDiagramWorkbenchPart)
		{
			final IDiagramWorkbenchPart part = (IDiagramWorkbenchPart) workbenchPart;
			try
			{
				new WorkspaceModifyDelegatingOperation(new IRunnableWithProgress()
				{
					public void run(IProgressMonitor monitor) throws InterruptedException, InvocationTargetException
					{
						
						test(part.getDiagramEditPart(), part.getDiagram()); //El equivalente a runValidation
						//ArrayList<Object> elementsToDraw= new ArrayList<>();
						//elementsToDraw.add(objectToMarkTest);
						//colorDiagramElements(elementsToDraw);
						highLightDiagramElements(objectToMarkAndHighlight);
					}
				}).run(new NullProgressMonitor());
			} 
			catch (InvocationTargetException e)
			{
				e.printStackTrace();
			} 
			catch (InterruptedException e)
			{	
				e.printStackTrace();
			}
			
			
		}
	}

	
	private void test(DiagramEditPart diagramEditPart, View view) //El equivalente a validate
	{
		IFile target = view.eResource()!=null ? WorkspaceSynchronizer.getFile(view.eResource()) : null;
		//El target es el notation file del archivo de papyrus
		if(target!=null)
		{
			//TODO Borrar los marcadores existentes aca
			
		}
		//System.out.println("EL objeto que esta tratando de marcar: " + objectToMarkTest);
		Diagnostic diagnostic = new BasicDiagnostic(Diagnostic.WARNING, "a", 1, "el mensaje de error del verificador", new Object[]{objectToMarkAndHighlight}); // TODO crear el diagnostic
		
//		EObject temp = (EObject)objectToMarkTest;
//		EObject modelRoot = temp.eResource().getContents().get(0);
//		EList<EObject> modelElements = modelRoot.eContents();
//		System.out.println("los elementos del modelo" + modelRoot.eContents());
//		
//		Object[] prueba = new Object [modelElements.size()];
//		for(int i=0; i< modelElements.size();i++)
//		{
//			prueba[i]= modelElements.get(i);
//		}
		
		//Diagnostic diagnostic = new BasicDiagnostic(Diagnostic.ERROR, "a", 1, "el mensaje", new Object[]{prueba[0]});
		
		createMarkers(target,diagnostic, diagramEditPart);
		
	}

	private void createMarkers(IFile target, Diagnostic diagnostic, DiagramEditPart diagramEditPart)
	{
		
		if(diagnostic.getSeverity() == Diagnostic.OK) 
		{
			return; // La verificacion dice que no hay que marcar a ningun elemento
		}
		
		//En teoria hay un diagnostico raiz
		final Diagnostic rootStatus = diagnostic;
		List allDiagnostics = new ArrayList();
		UMLDiagramEditorUtil.LazyElement2ViewMap element2ViewMap = new UMLDiagramEditorUtil.LazyElement2ViewMap(diagramEditPart.getDiagramView(), collectTargetElements(rootStatus, new HashSet <EObject>(), allDiagnostics));
		//for(Iterator it = diagnostic.getChildren().iterator(); it.hasNext();)
		//{System.out.println("Y aca");
			//Diagnostic nextDiagnostic = (Diagnostic)it.next();
		Diagnostic nextDiagnostic=diagnostic;
		//System.out.println("El target: " + target);
		//System.out.println(diagramEditPart.getViewer());
			//{
				List data = nextDiagnostic.getData();
				//System.out.println("Que es data: " + data);
				//if(data != null && !data.isEmpty() && data.get(0) instanceof EObject)
				//{System.out.println("llegasss");
				
				//
				ArrayList a = (ArrayList) data.get(0);
				
					EObject element = (EObject) a.get(0);
					
					View view = UMLDiagramEditorUtil.findView(diagramEditPart, element, element2ViewMap);
					addMarker(diagramEditPart.getViewer(), target, view.eResource().getURIFragment(view), EMFCoreUtil.getQualifiedName(element, true), nextDiagnostic.getMessage(), diagnosticToStatusSeverity(nextDiagnostic.getSeverity()));
				//}
			//}
		//}
		
		
	}
	
	private static void addMarker(EditPartViewer viewer, IFile target, String elementId, String location, String message, int statusSeverity)
	{
		if(target ==null)
		{//System.out.println("era null");
			return;
		}
		//System.out.println("no era null");
		UMLMarkerNavigationProvider.addMarker(target, elementId, location, message, statusSeverity);
	}

	private Set<EObject> collectTargetElements(Diagnostic diagnostic, Set<EObject> targetElementCollector, List allDiagnostics)
	{
		List data = diagnostic.getData();
		EObject target = null;
		if(data != null && !data.isEmpty() && data.get(0) instanceof EObject)
		{
			target = (EObject) data.get(0);
			targetElementCollector.add(target);
			allDiagnostics.add(diagnostic);
		}
		
		if(diagnostic.getChildren() != null && !diagnostic.getChildren().isEmpty())
		{
			for (Iterator it = diagnostic.getChildren().iterator(); it.hasNext();)
			{
				collectTargetElements((Diagnostic)it.next(), targetElementCollector, allDiagnostics);
				
			}
		}
		
		return targetElementCollector;

	}
	

	
	private static int diagnosticToStatusSeverity(int diagnosticSeverity)
	{
		
		if(diagnosticSeverity == Diagnostic.OK)
		{
			return IStatus.OK;
		}
		else if(diagnosticSeverity == Diagnostic.INFO)
		{
			return IStatus.INFO;
		}
		else if(diagnosticSeverity == Diagnostic.WARNING)
		{
			return IStatus.WARNING;
		}
		else if(diagnosticSeverity == Diagnostic.ERROR || diagnosticSeverity == Diagnostic.CANCEL)
		{
			return IStatus.ERROR;
		}
		return IStatus.INFO;
	}
	
	public void highLightDiagramElements(Object elementsToMark)
    {
    	
    	try
    	{
    		//Aca se esta muriendo
    		//serviceRegistry = ServiceUtilsForActionHandlers.getInstance().getServiceRegistry();
    		//container = ServiceUtils.getInstance().getISashWindowsContainer(serviceRegistry);

	    	IEditorPart activeEditor = container.getActiveEditor();
	    	//System.out.println(activeEditor);
	    	EList el = ((org.eclipse.papyrus.uml.diagram.clazz.UmlClassDiagramForMultiEditor) activeEditor).getDiagram().getChildren();
	    	Iterator<ShapeImpl> iter = el.iterator();
	    	
	    	ArrayList elementsToMarkArray=(ArrayList) elementsToMark;
	    	for (Object object : elementsToMarkArray)
	    	{
	    		boolean correspondingShapeFound=false;
	    		while (!correspondingShapeFound && iter.hasNext())
	        	{
	        	    ShapeImpl si = iter.next();
	        	    //TODO Esto lo tengo que cambiar
	        	    if(si.basicGetElement().equals(object)) //La comparacion probablemente no deberia ser un equal
	        	    {
	        	    	final org.eclipse.gmf.runtime.notation.Shape shape = (org.eclipse.gmf.runtime.notation.Shape) si;
	
	        	    	final int myColor = 10265827; //red
	        	    	TransactionalEditingDomain ted = TransactionUtil.getEditingDomain(shape);
	        	    	ted.getCommandStack().execute(new RecordingCommand(ted) {
	        	    		protected void doExecute() {
	        	    			shape.setFillColor(myColor);
	        	    		}
	        	    	});
	        	    	
	        	    	correspondingShapeFound=true;
	        	    }
	    
	        	}
				
			}
    	
    	
    	
    	}
    	catch(Exception e)
    	{
    		
    	}
    }
	
	

}
